home *** CD-ROM | disk | FTP | other *** search
- /*
- ==============================================================================
- WordUp Graphics Toolkit Version 5.0
- Demonstration Program 55
-
- This program rotates 3 individual objects at the same time and uses Gouraud
- shading to display them. It is a more complex version of the first 3D demo
- since each object has a number of independant variables, and the area each
- occupies on the screen is dealt with for each object for maximum speed.
-
- *** PROJECT ***
- This program requires the file WGT5_WC.LIB, and WGT3D_WC.LIB to be linked.
-
- *** DATA FILES ***
- You must have the MYTRI.3D, MYCUBE.3D, MYCYL.3D, and 3DDEMO.PAL files in
- your executable dir.
- WATCOM C++ VERSION
- ==============================================================================
- */
- #include <conio.h>
- #include <math.h>
- #include <stdlib.h>
- #include <dos.h>
- #include <wgt3d.h>
- #include <wgt5.h>
-
- /* WGT 3D Object File Format
- The following is a description of the file format used in the 3D demos.
-
- The first line contains the identification string
- "WGT 3D Object File"
-
- Then the number of points in the file is on a separate line.
- Each point is then stated, with the following format:
- x_coord y_coord z_coord sx_value sy_value
-
- With hollow and solid polygons, you can use sx as the color of the polygon.
- With Gouraud shading, sx is the color at that point.
- With Texture mapping, sx,sy is the offset into the texture bitmap.
-
- A blank line follows, and then the number of faces is on a new line.
- Each face is described as a 4 point sequence, using the points stated above.
- Point numbers start at 0.
- On the same line, a polygon type number is given.
- 0 means hollow
- 1 means solid
- 2 means lighted Gouraud (brighter closer to you)
- 3 means set Gouraud (uses value stored by the vertices above)
- 4 means texture mapped (not used in this demo)
-
- For example, to make a face with points 0-3, with set Gouraud shading,
- the line would be
- 0 1 2 3 3
-
- Here is an example image with one polygon:
-
- WGT 3D Object File
- 4
- -25 -25 50 140 0
- 25 -25 50 195 0
- 25 25 50 140 0
- -25 25 50 195 0
-
- 1
- 0 1 2 3 3
- */
-
- #define HOLLOW 0
- #define SOLID 1
- #define GOURAUD 2
- #define SETGOURAUD 3
-
- /* Routines used in this program */
- void loadobject(char *,point3d *,short);
- void clear_last(void);
- void update_screen(void);
- void calculate_depth(void);
- void sort_polys(void);
- void draw_polys(void);
- void rotate_objects(void);
-
-
- point3d mycube[9]; /* Store data points for each object */
- point3d mytri[9];
- point3d mycyl[9];
-
- point3d finp[90]; /* Stores the final, rotated points */
- short numpts[3]; /* Number of points in each object */
- tpolypoint mypoly[4]; /* Used to draw one polygon at a time */
-
- short rendermethod;
- char c;
-
- short sortpoly[100];
- short ztotal[100];
-
- short maxpoly = 300;
- short totalpoly = 0;
- short rot;
-
- short faces[200][4];
- short facetype[200];
- short faceowner[200];
-
- block other;
- color pal[256];
- short d, e;
-
- typedef struct {
- short x1;
- short y1;
- short x2; /* Used to keep track what portion of the */
- short y2; /* screen has been changed, so we can update */
- } rect; /* the least amount of video memory */
-
-
- typedef struct
- {
- rect lastrect, thisrect;
- short addx, addy, addz;
- short curx, cury, curz;
- } object3d;
-
- object3d myobject[3];
-
- short xdir[3] = {1, -1, 1};
- short ydir[3] = {1, 1, -1};
- short zdir[3] = {-1, 1, 1};
- short xpos[3] = {0, 200, -200};
- short ypos[3] = {0, 0, 0};
- short zpos[3] = {0, 0, 0};
-
- int updates, timer;
-
- void loadobject (char *fname, point3d *mypoints, short obj)
- /* Loads a 3D object file */
- {
- short i;
- FILE *objfile;
- char blank[80];
- short addnum = 0;
-
- for (i = 0; i < obj; i++)
- addnum += numpts[i];
-
- objfile = fopen (fname, "rt");
-
- fscanf (objfile,"%s %s %s %s\n", blank, blank, blank, blank);
-
- /* Number of points in this object */
- fscanf (objfile, "%hd\n", &maxpoly);
-
- numpts[obj] = maxpoly;
-
- /* Load the points */
- for (i = 0; i < maxpoly; i++)
- fscanf(objfile, "%hd %hd %hd %hd %hd\n", &mypoints[i].x, &mypoints[i].y,
- &mypoints[i].z, &mypoints[i].sx, &mypoints[i].sy);
-
- /* Number of faces in this object */
- fscanf (objfile, "\n%hd\n", &maxpoly);
- for (i = 0; i < maxpoly; i++)
- {
- for (e = 0; e < 4; e++)
- {
- fscanf (objfile, "%hd ", &faces[i + totalpoly][e]);
- faces[i + totalpoly][e] += addnum;
- }
- fscanf (objfile, "%hd\n", &facetype[i + totalpoly]);
- faceowner[i + totalpoly] = obj;
- }
- totalpoly += maxpoly;
- fclose (objfile);
- }
-
-
- void clear_last (void)
- /* Clears out the last regions of the screen where the objects were */
- {
- short i;
- rect *lr;
-
- for (i = 0; i < 3; i++)
- {
- lr = &myobject[i].lastrect;
-
- /* Do clipping for smallest area update */
- if (lr->x1 < 0)
- lr->x1 = 0;
- if (lr->x2 > 319)
- lr->x2 = 319;
- if (lr->y1 < 0)
- lr->y1 = 0;
- if (lr->y2 > 199)
- lr->y2 = 199;
-
- wsetcolor (0);
- /* Change the previous line to the one below in order to see the updating
- rectangular regions */
-
- wbar (lr->x1, lr->y1, lr->x2, lr->y2);
- /* Clear out the area that was drawn in last frame */
- }
- }
-
-
- void update_screen (void)
- /* Copy the regions of the background screen onto the visual screen */
- {
- rect *tr;
- rect *lr;
- short i;
-
- for (i = 0; i < 3; i++)
- {
- tr = &myobject[i].thisrect;
- lr = &myobject[i].lastrect;
-
- if (lr->x1 > tr->x1)
- lr->x1 = tr->x1;
- if (lr->x2 < tr->x2)
- lr->x2 = tr->x2;
- if (lr->y1 > tr->y1)
- lr->y1 = tr->y1;
- if (lr->y2 < tr->y2)
- lr->y2 = tr->y2;
- /* See if the previous frame was larger in any direction. If it is, enlarge
- the area so it will copy black over the previous frame. */
-
- /* Do clipping */
- if (lr->x1 < 0)
- lr->x1 = 0;
- if (lr->x2 > 319)
- lr->x2 = 319;
- if (lr->y1 < 0)
- lr->y1 = 0;
- if (lr->y2 > 199)
- lr->y2 = 199;
-
- wcopyscreen (lr->x1, lr->y1, lr->x2, lr->y2, other, lr->x1, lr->y1, NULL);
- /* Copy from our second page to the visual page. */
-
- lr->x1 = tr->x1;
- lr->y1 = tr->y1;
- lr->x2 = tr->x2;
- lr->y2 = tr->y2;
-
- /* Make the last rectangle = current rectangle */
- }
- }
-
-
- void calculate_depth (void)
- /* Prepare the ztotal array for sorting polygons by z value */
- {
- short d, e;
-
- for (d = 0; d < maxpoly; d++)
- {
- sortpoly[d] = d;
- ztotal[d] = 0;
- for (e = 0; e < 4; e++)
- ztotal[d] += finp[faces[d][e]].z;
- ztotal[d] /= 4;
- }
- }
-
-
- void sort_polys (void)
- /* Sort those polys using slow bubble sort */
- /* There are only about 20 polys max so it probably doesn't matter what
- sorting method you use here. */
- {
- short d, e, temp;
-
- for (d = 0; d < maxpoly - 1; d++)
- for (e = d + 1; e < maxpoly; e++)
- {
- if (ztotal[sortpoly[e]] > ztotal[sortpoly[d]])
- {
- temp = sortpoly[e];
- sortpoly[e] = sortpoly[d];
- sortpoly[d] = temp;
- }
- }
- }
-
-
- void check_rectangle (short obj, short x, short y)
- /* Enlarge the update rectangle if needed */
- {
- rect *tr;
-
- tr = &myobject[obj].thisrect;
-
- if (x < tr->x1)
- tr->x1 = x;
- if (x > tr->x2)
- tr->x2 = x;
-
- if (y < tr->y1)
- tr->y1 = y;
- if (y > tr->y2)
- tr->y2 = y;
- /* See if the polygon is larger than the current area to update.
- If it is, enlarge the area so all polygons fit inside. */
- }
-
-
- void draw_polys (void)
- /* Draw all of the polygons in order, using our rendering method */
- {
- short d, e;
- short cp;
-
- for (d = 0; d < maxpoly; d++)
- {
- cp = sortpoly[d];
- for (e = 0; e < 4; e++)
- {
- mypoly[e].x = finp[faces[cp][e]].x;
- mypoly[e].y = finp[faces[cp][e]].y;
- if (facetype[cp] != GOURAUD)
- {
- /* ARGH! This is very inflexible this way! */
- if (cp < 6)
- mypoly[e].sx = mycube[faces[cp][e]].sx;
- else if (cp < 11)
- mypoly[e].sx = mytri[faces[cp][e] - 8].sx;
- else mypoly[e].sx = mycyl[faces[cp][e] - 13].sx;
- }
- else
- {
- mypoly[e].sx = (255 - finp[faces[cp][e]].z / 7);
- if (mypoly[e].sx < 2)
- mypoly[e].sx = 2;
- if (mypoly[e].sx > 250)
- mypoly[e].sx = 250;
- }
- check_rectangle (faceowner[cp], mypoly[e].x, mypoly[e].y);
- }
-
- wsetcolor (mypoly[0].sx);
-
- if (facetype[cp] == HOLLOW)
- whollowpoly (mypoly, 4, 0, 0, CLOSED_POLY);
- else if (facetype[cp] == SOLID)
- wsolidpoly (mypoly, 4, 0, 0, NULL);
- if ((facetype[cp] == GOURAUD) || (facetype[cp] == SETGOURAUD))
- wgouraudpoly (mypoly, 4, 0, 0);
- }
- }
-
-
- void rotate_objects (void)
- /* Make objects spin and rotate all the points */
- {
- short i;
-
- for (i = 0; i < 3; i++)
- {
- myobject[i].curx += myobject[i].addx;
- myobject[i].cury += myobject[i].addy;
- myobject[i].curz += myobject[i].addz;
-
- if (myobject[i].curx > 359)
- myobject[i].curx -= 360;
- if (myobject[i].cury > 359)
- myobject[i].cury -= 360;
- if (myobject[i].curz > 359)
- myobject[i].curz -= 360;
- if (myobject[i].curx < 0)
- myobject[i].curx += 360;
- if (myobject[i].cury < 0)
- myobject[i].cury += 360;
- if (myobject[i].curz < 0)
- myobject[i].curz += 360;
-
- wsetrotation (myobject[i].curx, myobject[i].cury, myobject[i].curz);
-
- move_x = xpos[i];
- move_y = ypos[i];
- move_z = zpos[i];
-
- switch (i)
- {
- case 0: wrotatepoints (mycube, finp, numpts[0]);
- break;
- case 1: wrotatepoints (mytri, &finp[numpts[0]], numpts[1]);
- break;
- case 2: wrotatepoints (mycyl, &finp[numpts[0]+numpts[1]], numpts[2]);
- break;
- }
- }
- }
-
-
- void bounce_object (void)
- /* Make objects bounce in 3D space. When they change direction, they also
- change their rotational motion */
- {
- short i;
-
- for (i = 0; i < 3; i++)
- {
- xpos[i] += xdir[i] * 4;
- ypos[i] += ydir[i] * 4;
- zpos[i] += zdir[i] * 4;
-
- if (xpos[i] > 400)
- {
- xdir[i] = -1;
- myobject[i].addx = -4;
- }
- if (ypos[i] > 200)
- {
- ydir[i] = -1;
- myobject[i].addy = -4;
- }
- if (zpos[i] > -100)
- {
- zdir[i] = -1;
- myobject[i].addz = -4;
- }
- if (xpos[i] < -400)
- {
- xdir[i] = 1;
- myobject[i].addx = 4;
- }
- if (ypos[i] < -200)
- {
- ydir[i] = 1;
- myobject[i].addy = 4;
- }
- if (zpos[i] < -1900)
- {
- zdir[i] = 1;
- myobject[i].addz = 4;
- }
- }
- }
-
-
- void invert_rectangles (void)
- {
- short i;
-
- for (i = 0; i < 3; i++)
- {
- myobject[i].thisrect.x1 = 319;
- myobject[i].thisrect.y1 = 199;
- myobject[i].thisrect.x2 = 0;
- myobject[i].thisrect.y2 = 0;
- }
- }
-
-
- void timerctr (void)
- {
- timer++;
- }
-
-
- void main (void)
- {
- short i;
- short oldmode;
-
- oldmode = wgetmode ();
-
- if ( !vgadetected () )
- {
- printf ("Error - VGA card required for any WGT program.\n");
- exit (0);
- }
- printf ("WGT Example #55\n\n");
-
- printf ("3d Object Demo #2\n\n");
- printf ("Choose your rendering type:\n");
- printf ("0: Wireframe\n");
- printf ("1: Solid\n");
- printf ("2: Gouraud\n");
- printf ("3: Set Gouraud\n");
-
- scanf ("%i", &rendermethod);
-
- vga256 ();
-
- winit3d ();
- winitpoly (WGT_SYS.yres);
-
- other = wnewblock (0, 0, 319, 199);
- wloadpalette ("3ddemo.pal", pal);
-
- if (rendermethod == GOURAUD) /* Lighted Gouraud, so create a palette with
- gradually changing colors. */
- {
- for (i = 0; i < 64; i++)
- wsetrgb (i, 0, 0, i, pal);
- for (i = 64; i < 256; i++)
- wsetrgb (i, (i - 64) / 2, (i - 64) / 2, 64, pal);
- }
-
- wsetpalette(0, 255, pal);
-
- maxpoly = 0;
- loadobject ("mycube.3d", mycube, 0);
- loadobject ("mytri.3d", mytri, 1);
- loadobject ("mycyl.3d", mycyl, 2);
-
- for (i = 0; i < totalpoly; i++)
- facetype[i] = rendermethod;
-
- for (i = 0; i < 3; i++)
- {
- xpos[i] = ((rand () % 400) - 200);
- ypos[i] = ((rand () % 200) - 100);
- zpos[i] = -((rand () % 1800) + 100);
- }
-
- wsetscreen (other);
-
- maxpoly = totalpoly;
-
- /* Main loop */
- timer = 0;
- winittimer ();
- wstarttimer (timerctr, TICKS(100));
- do {
- invert_rectangles ();
-
- clear_last ();
-
- bounce_object ();
- rotate_objects ();
- calculate_depth ();
- sort_polys ();
- draw_polys ();
- update_screen ();
- updates++;
- } while (!kbhit ());
- wstoptimer ();
- wdonetimer ();
- // get final time
-
- wdeinitpoly ();
- wsetmode (oldmode);
-
- printf ("\nElapsed time (hundredths of seconds): %i", timer);
- printf ("\n# updates: %d", updates);
- printf ("\nAverage frame rate: %2.2f frames/sec\n", (float)updates / (float)(timer / 100));
- }
-
-
-